package com.example.administrator.bitmaputils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.widget.ImageView;

import java.io.File;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

public abstract class ImageCache {
	private HashMap<String, SoftReference<Bitmap>> mCache = new HashMap<String, SoftReference<Bitmap>>();
	private HashMap<String, Integer> mFailed = new HashMap<String, Integer>();
	private Handler mWorkHandler;

	protected abstract Context getContext ();
	protected abstract Handler getHandler ();

	public ImageCache() {
		initWorker ();
	}

	public static interface ImgLoad {
		public void onImgLoad (Bitmap bmp, String path);
	}

	/**
	 * 绑定图片显示
	 * @param img
	 * @param path
	 */
	public void Bind (ImageView img, String path) {
		img.setTag(path);
		Bitmap bmp = getBitmapFromCache (path);
		if (bmp != null) {
			img.setImageBitmap(bmp);
		}
		else if (mFailed.containsKey(path)) {
			img.setImageResource(R.drawable.file_loading_icon);
		}
		else {
			asyncLoadImg (img, path, null);
		}
	}

	/**
	 * 绑定图片显示
	 * @param img
	 * @param path
	 */
	public void Bind (ImageView img, String path, ImgLoad dele) {
		img.setTag(path);
		Bitmap bmp = getBitmapFromCache (path);
		if (bmp != null) {
			img.setImageBitmap(bmp);
			dele.onImgLoad(bmp, path);
		}
		else if (mFailed.containsKey(path)) {
			img.setImageResource(R.drawable.file_loading_icon);
			dele.onImgLoad(bmp, path);
		}
		else {
			asyncLoadImg (img, path, dele);
		}
	}

	/**
	 * 绑定图片显示
	 * @param img
	 * @param path
	 */
	public Bitmap BindSync (ImageView img, String path) {
		img.setTag(path);
		Bitmap bmp = getBitmapFromCache (path);
		if (bmp != null) {
			img.setImageBitmap(bmp);
		}
		else if (mFailed.containsKey(path)) {
			img.setImageResource(R.drawable.file_loading_icon);
		}
		else {
			bmp = loadThumb (path);
			img.setImageBitmap(bmp);
		}
		return bmp;
	}


	public boolean isImgCached (String path) {
		return mCache.containsKey(path) || mFailed.containsKey(path);
	}

	private Bitmap getBitmapFromCache (String path) {
		SoftReference<Bitmap> bmp = mCache.get(path);
		if (bmp != null && bmp.get() != null) {
			return bmp.get();
		}
		return null;
	}


	private void asyncLoadImg (final ImageView iv, final String path, final ImgLoad dele) {
		iv.setImageResource(R.drawable.file_loading_icon);
		mWorkHandler.post(new Runnable() {
			public void run () {
				if ( !((String) iv.getTag()).equals(path)) {
					return;
				}
				Bitmap bmp = loadImg (path);
				updateImg (iv, path, bmp, dele);
			}
		});
	}

	private void updateImg (final ImageView iv, final String path, final Bitmap bmp, final ImgLoad dele) {
		if (bmp == null) {
			if (dele != null) {
				dele.onImgLoad(null, path);
			}
			return;
		}
		getHandler().post(new Runnable() {
			public void run () {
				if ( !((String) iv.getTag()).equals(path)) {
					return;
				}
				iv.setImageBitmap(bmp);
				if (dele != null) {
					dele.onImgLoad(bmp, path);
				}
			}
		});
	}

	private Bitmap loadImg (String path) {
		try {
			File f = new File(path);
			if (!f.exists()) {
				mFailed.put(path, 1);
				return null;
			}

			byte[] result = null;
			int degree = BitmapUtils.readPictureDegree(path);
			if (degree != 0) {
				result = BitmapUtils.getOrientationImageForShow(getContext(), path, 144, 144, true, 75, degree);
			}
			else {
				result = BitmapUtils.getResizedImageData(getContext(), Uri.fromFile(new File(path)), 75, 144, 144);
			}

			if (result == null) {
				mFailed.put(path, 1);
				return null;
			}

			Bitmap bitmap = BitmapUtils.loadBitmap(result);
			if (bitmap == null) {
				mFailed.put(path, 1);
				return null;
			}

			SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
			mCache.put(path, softBitmap);
			return bitmap;
		} catch (Exception e) {
//			Trace.T("error img " + e.getMessage() + " path: " + path);
			return null;
		}
	}

	private Bitmap loadThumb (String path) {
		Bitmap bitmap = BitmapFactory.decodeFile (path, null);
		SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
		mCache.put(path, softBitmap);
		return bitmap;
	}

	/**
	 * 必须要调用该函数释放资源
	 */
	public void clearCache () {
		Set<Entry<String, SoftReference<Bitmap>>> sets = mCache.entrySet();
		for (Entry<String, SoftReference<Bitmap>> e : sets) {
			if (e.getValue() != null && e.getValue().get() != null) {
				e.getValue().get().recycle();
			}
		}
		mCache.clear();
		mFailed.clear();
	}

	/**
	 * 释放更新线程 宿主的onDestroy()调用
	 */
	public void destroyWorker () {
		if (mWorkHandler == null) {
			return;
		}
		mWorkHandler.post(new Runnable() {
			public void run () {
				Looper.myLooper().quit();
			}
		});
		mWorkHandler = null;
	}

	private void initWorker () {
		new Thread() {
			public void run () {
				Looper.prepare();
				mWorkHandler = new Handler();
				Looper.loop();
			}
		}.start();
	}

	/**
	 * 重置特定图片
	 * @param path
	 */
	public void resetImg (String path) {
		mCache.remove(path);
		mFailed.remove(path);
	}
}
